package co.yixiang.yshop.module.order.service.storeaftersales;

import co.yixiang.yshop.framework.common.enums.OrderDefaultRuleEnum;
import co.yixiang.yshop.framework.common.enums.OrderInfoEnum;
import co.yixiang.yshop.framework.common.enums.ShopCommonEnum;
import co.yixiang.yshop.framework.common.pojo.PageResult;
import co.yixiang.yshop.framework.redis.util.RedissonUtil;
import co.yixiang.yshop.module.member.controller.admin.user.vo.UserRespVO;
import co.yixiang.yshop.module.member.convert.user.UserConvert;
import co.yixiang.yshop.module.member.dal.dataobject.user.MemberUserDO;
import co.yixiang.yshop.module.member.dal.mysql.user.MemberUserMapper;
import co.yixiang.yshop.module.member.enums.BillDetailEnum;
import co.yixiang.yshop.module.message.enums.WechatTempateEnum;
import co.yixiang.yshop.module.message.mq.message.WeixinNoticeMessage;
import co.yixiang.yshop.module.message.mq.producer.WeixinNoticeProducer;
import co.yixiang.yshop.module.order.controller.admin.storeaftersales.vo.StoreAfterSalesPageReqVO;
import co.yixiang.yshop.module.order.controller.admin.storeaftersales.vo.StoreAfterSalesRespVO;
import co.yixiang.yshop.module.order.controller.admin.storeaftersales.vo.StoreAfterSalesUpdateReqVO;
import co.yixiang.yshop.module.order.controller.admin.storeorderrule.vo.StoreOrderRuleVO;
import co.yixiang.yshop.module.order.controller.app.afterorder.param.AppOrderRefundParam;
import co.yixiang.yshop.module.order.convert.storeaftersales.StoreAfterSalesConvert;
import co.yixiang.yshop.module.order.dal.dataobject.storeaftersales.StoreAfterSalesDO;
import co.yixiang.yshop.module.order.dal.dataobject.storeaftersalesitem.StoreAfterSalesItemDO;
import co.yixiang.yshop.module.order.dal.dataobject.storeorder.StoreOrderDO;
import co.yixiang.yshop.module.order.dal.dataobject.storeordercartinfo.StoreOrderCartInfoDO;
import co.yixiang.yshop.module.order.dal.dataobject.storeorderdetail.StoreOrderDetailDO;
import co.yixiang.yshop.module.order.dal.mysql.storeaftersales.StoreAfterSalesMapper;
import co.yixiang.yshop.module.order.dal.mysql.storeaftersalesitem.StoreAfterSalesItemMapper;
import co.yixiang.yshop.module.order.dal.mysql.storeorder.StoreOrderMapper;
import co.yixiang.yshop.module.order.dal.mysql.storeordercartinfo.StoreOrderCartInfoMapper;
import co.yixiang.yshop.module.order.dal.mysql.storeorderdetail.StoreOrderDetailMapper;
import co.yixiang.yshop.module.order.dal.redis.ofterorder.AfterOrderRedisDAO;
import co.yixiang.yshop.module.order.enums.*;
import co.yixiang.yshop.module.order.service.storeaftersalesstatus.StoreAfterSalesStatusService;
import co.yixiang.yshop.module.order.service.storeorder.AppStoreOrderService;
import co.yixiang.yshop.module.order.service.storeorderrule.StoreOrderRuleService;
import co.yixiang.yshop.module.product.enums.product.StockBackTypeEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

import static co.yixiang.yshop.framework.common.exception.util.ServiceExceptionUtil.exception;
import static co.yixiang.yshop.module.order.enums.ErrorCodeConstants.*;

/**
 * 售后记录 Service 实现类
 *
 * @author yshop
 */
@Slf4j
@Service
@Validated
public class StoreAfterSalesServiceImpl implements StoreAfterSalesService {

    @Resource
    private StoreAfterSalesMapper storeAfterSalesMapper;
    @Resource
    private StoreAfterSalesItemMapper storeAfterSalesItemMapper;
    @Resource
    private MemberUserMapper memberUserMapper;
    @Resource
    private StoreOrderMapper storeOrderMapper;
    @Resource
    private AfterOrderRedisDAO afterOrderRedisDAO;
    @Resource
    private AppStoreOrderService appStoreOrderService;
    @Resource
    private StoreAfterSalesStatusService storeAfterSalesStatusService;
    @Resource
    private StoreOrderRuleService storeOrderRuleService;

    @Resource
    private StoreOrderCartInfoMapper storeOrderCartInfoMapper;

    @Resource
    private StoreOrderDetailMapper orderDetailMapper;

    @Resource
    private RedissonUtil redissonUtil;
    @Resource
    private WeixinNoticeProducer weixinNoticeProducer;


    @Override
    public void updateStoreAfterSales(StoreAfterSalesUpdateReqVO updateReqVO) throws Exception {
        //售后订单的id
        Long id = updateReqVO.getId();
        // 校验存在
        validateStoreAfterSalesExists(id);
        this.salesCheck(id, updateReqVO.getOrderCode(), updateReqVO.getType(),
                updateReqVO.getConsignee(), updateReqVO.getPhoneNumber(), updateReqVO.getAddress());

    }

    @Override
    public void taskAfterSalesConfirm(Long id) throws Exception {
        StoreAfterSalesDO storeAfterSales = storeAfterSalesMapper.selectById(id);
        StoreOrderRuleVO orderRuleCache = storeOrderRuleService.getOrderRuleCache();
        this.salesCheck(
                storeAfterSales, AfterTypeEnum.AGREE.getValue(),
                orderRuleCache.getConsignee(),
                orderRuleCache.getPhoneNumber(),
                orderRuleCache.getAddress()
        );
    }

    @Override
    public void taskAfterSalesCancel(Long id) throws Exception {
        StoreAfterSalesDO storeAfterSales = storeAfterSalesMapper.selectById(id);
        this.salesCheck(
                storeAfterSales, AfterTypeEnum.CANCEL.getValue(),
                null, null, null
        );
    }

    private void salesCheck(StoreAfterSalesDO storeAfterSales, Integer approvalStatus, String consignee, String phoneNumber, String address) throws Exception {
        Long salesId = storeAfterSales.getId();
        String orderCode = storeAfterSales.getOrderCode();
        Long userId = storeAfterSales.getUserId();
        Integer currentState = storeAfterSales.getState();
        //处理结果的类型枚举
        AfterChangeTypeEnum optEnum = null;
        //处理后的售后订单状态
        Integer newStoreAfterSalesState = null;
        //审核成功
        if (AfterTypeEnum.AGREE.getValue().equals(approvalStatus)) {
            // 退款参数
            AppOrderRefundParam param = new AppOrderRefundParam(salesId, orderCode,
                    storeAfterSales.getRefundAmount(), StockBackTypeEnum.DEFAULT.getValue(),
                    storeAfterSales.getRefundIntegral(), BillDetailEnum.TYPE_14);
            String logTemplate = "=> 售后订单:{} =订单号：{} =userId：{} {}";
            //退货退款
            if (AfterTypeEnum.RETURNS_REFUNDS.getValue().equals(storeAfterSales.getServiceType())) {
                switch (AfterSalesStatusEnum.toType(currentState)) {
                    case PENDING_REVIEW://已提交等待平台审核
                        //通过售后走这里，需要加上商家地址，联系方式等，状态变为：平台已审核,等待用户发货/退款
                        if (StringUtils.isEmpty(consignee) || StringUtils.isEmpty(phoneNumber) || StringUtils.isEmpty(address)) {
                            throw exception(ORDER_ADDRESS_REQUERED);
                        }
                        storeAfterSales.setConsignee(consignee);
                        storeAfterSales.setPhoneNumber(phoneNumber);
                        storeAfterSales.setAddress(address);
                        optEnum = AfterChangeTypeEnum.AUDIT_SUCCESS;
                        newStoreAfterSalesState = AfterSalesStatusEnum.AUDITED.getValue();
                        log.info(logTemplate, salesId, orderCode, userId, AfterSalesStatusEnum.AUDITED.getDesc());

                        Integer afterSalesFailCancel = storeOrderRuleService.getOrderRuleCache().getAfterSalesFailCancel();
                        // 售后审核通过后，多少天用户没寄回，售后自动失败
                        OrderDefaultRuleEnum ruleEnum = OrderDefaultRuleEnum.AFTER_SALES_ORDER_USER_NO_RETURN_GOODS;
                        redissonUtil.delayedOffer(ruleEnum.getKey(), salesId, afterSalesFailCancel, ruleEnum.getUnit());
                        break;
                    case AUDITED://平台已审核,等待用户发货/退款
                        log.info(logTemplate + ",无需重复审核", salesId, orderCode, userId, AfterSalesStatusEnum.AUDITED.getDesc());
                        break;
                    case USER_SHIPPED://用户已发货
                        //退款金额大于0才生成退款单
                        appStoreOrderService.orderRefund(param);
                        optEnum = AfterChangeTypeEnum.PAYMENT;
                        newStoreAfterSalesState = AfterSalesStatusEnum.REFUND_SUCCESS.getValue();
                        log.info(logTemplate, salesId, orderCode, userId, AfterSalesStatusEnum.REFUND_SUCCESS.getDesc());
                        break;
                    case REFUND_SUCCESS://用户退款成功
                        log.info(logTemplate + ",无需重复退款", salesId, orderCode, userId, AfterSalesStatusEnum.REFUND_SUCCESS.getDesc());
                        break;
                    case USER_CANCELLED://用户已取消
                        log.info(logTemplate, salesId, orderCode, userId, AfterSalesStatusEnum.USER_CANCELLED.getDesc());
                        break;
                    case MERCHANT_REJECTION://商家拒绝
                        log.info(logTemplate, salesId, orderCode, userId, AfterSalesStatusEnum.MERCHANT_REJECTION.getDesc());
                        break;
                }
            } else {
                //仅仅退款,直接退款
                if (Objects.requireNonNull(AfterSalesStatusEnum.toType(currentState)) == AfterSalesStatusEnum.PENDING_REVIEW) {
                    appStoreOrderService.orderRefund(param);
                    optEnum = AfterChangeTypeEnum.PAYMENT;
                    newStoreAfterSalesState = AfterSalesStatusEnum.REFUND_SUCCESS.getValue();
                }
            }
        } else if (AfterTypeEnum.CANCEL.getValue().equals(approvalStatus)) {
            //取消
            if (Objects.requireNonNull(AfterSalesStatusEnum.toType(currentState)) == AfterSalesStatusEnum.AUDITED) {//平台已审核,等待用户发货/退款
                //重置订单相关状态
                this.resetSaleAfterOrder(orderCode, salesId);
                optEnum = AfterChangeTypeEnum.TIME_OUT_AUDIT_FAILED;
                newStoreAfterSalesState = AfterSalesStatusEnum.TIME_OUT_CANCELLED.getValue();
            }
        } else {
            //拒绝
            switch (AfterSalesStatusEnum.toType(currentState)) {
                case PENDING_REVIEW://已提交等待平台审核
                case AUDITED://平台已审核,等待用户发货/退款
                    //重置订单相关状态
                    this.resetSaleAfterOrder(orderCode, salesId);
                    optEnum = AfterChangeTypeEnum.AUDIT_FAILED;
                    newStoreAfterSalesState = AfterSalesStatusEnum.MERCHANT_REJECTION.getValue();
                    break;
                case USER_SHIPPED://用户已发货
                    log.info("=====用户 {} 对售后订单：{} 已经发货，无需处理", userId, salesId);
                    break;
                case REFUND_SUCCESS://用户退款成功
                    log.info("=====用户 {} 对售后订单：{} 已经退款成功，无需操作", userId, salesId);
                    break;
                case USER_CANCELLED://用户已取消
                    log.info("=====用户 {} 对售后订单：{} 已取消售后", userId, salesId);
                    break;
                case MERCHANT_REJECTION://商家拒绝
                    log.info("=====用户 {} 对售后订单：{} 已发货,无需拒绝", userId, salesId);
                    break;
            }
        }
        //操作后的售后订单新状态,
        if (newStoreAfterSalesState != null) {
            storeAfterSales.setState(newStoreAfterSalesState);
            storeAfterSalesMapper.updateById(storeAfterSales);
            //如果退款成功。更新订单
            if(AfterSalesStatusEnum.REFUND_SUCCESS.getValue().equals(newStoreAfterSalesState)){
                storeOrderMapper.update(StoreOrderDO.builder()
                        .refundStatus(OrderInfoEnum.REFUND_STATUS_HAVE_REFUNDED.getValue())
                        .status(OrderStatusEnum.STATUS_MINUS_REFUNDED.getValue())
                        .build(),new LambdaQueryWrapper<StoreOrderDO>()
                        .eq(StoreOrderDO::getOrderId,storeAfterSales.getOrderCode()));
            }

        }
        //添加订单操作记录
        if (optEnum != null) {
            addOrderOptLog(userId, salesId, optEnum);
        }

        //小程序
        weixinNoticeProducer.sendNoticeMessage( new WeixinNoticeMessage()
                .setUid(userId)
                .setOrderId(orderCode)
                .setTempkey(WechatTempateEnum.ORDER_AFTER_NOTICE.getValue())
                .setType(WechatTempateEnum.SUBSCRIBE.getValue()));
        //公众号
        weixinNoticeProducer.sendNoticeMessage( new WeixinNoticeMessage()
                .setUid(userId).setOrderId(orderCode)
                .setTempkey(WechatTempateEnum.ORDER_AFTER_NOTICE.getValue())
                .setType(WechatTempateEnum.TEMPLATES.getValue()));
    }

    //重置售后相关记录的状态
    private void resetSaleAfterOrder(String orderCode, Long salesId) {
        StoreOrderDO yxStoreOrder = this.findOrder(orderCode);
        Long orderId = yxStoreOrder.getId();
        // 查询售后中的订单明细，并回退状态
        this.resetOrderDetail(orderId, salesId);
        // 重置订单状态
        this.resetOrderInfo(yxStoreOrder);
        // 订单购物详情重置‘是否售后’字段
        this.resetOrderCartInfo(orderId);
    }

    //重置订单的状态
    private void resetOrderInfo(StoreOrderDO yxStoreOrder) {
        String orderId = yxStoreOrder.getOrderId();
        Long uid = yxStoreOrder.getUid();
        String o = afterOrderRedisDAO.get(orderId, uid);
        yxStoreOrder.setStatus(o == null ? 0 : Integer.parseInt(o));
        // 订单退款状态重置
        yxStoreOrder.setRefundStatus(OrderInfoEnum.REFUND_STATUS_NORMAL.getValue());
        storeOrderMapper.updateById(yxStoreOrder);
        afterOrderRedisDAO.delete(orderId, uid);
    }

    // 查询订单
    private StoreOrderDO findOrder(String orderCode) {
        return storeOrderMapper.selectOne(
                Wrappers.<StoreOrderDO>lambdaQuery().eq(StoreOrderDO::getOrderId, orderCode)
        );
    }

    /**
     * 订单购物详情重置‘是否售后’字段
     *
     * @param orderId 订单主键
     */
    private void resetOrderCartInfo(Long orderId) {
        List<StoreOrderCartInfoDO> yxStoreOrderCartInfos = storeOrderCartInfoMapper.selectList(
                Wrappers.<StoreOrderCartInfoDO>lambdaQuery()
                        .eq(StoreOrderCartInfoDO::getOid, orderId)
        );
        for (StoreOrderCartInfoDO yxStoreOrderCartInfo : yxStoreOrderCartInfos) {
            yxStoreOrderCartInfo.setIsAfterSales(ShopCommonEnum.YES.getValue());
            storeOrderCartInfoMapper.updateById(yxStoreOrderCartInfo);
        }
    }

    /**
     * 查询售后中的订单明细，并回退状态
     *
     * @param orderId 订单主键
     * @param salesId 售后记录id
     */
    private void resetOrderDetail(Long orderId, Long salesId) {
        //
        List<StoreOrderDetailDO> orderDetailDOS =
                orderDetailMapper.selectList(Wrappers.<StoreOrderDetailDO>lambdaQuery()
                        .eq(StoreOrderDetailDO::getOid, orderId)
                        .eq(StoreOrderDetailDO::getState, OrderDetailStateEnum.IN_AFTER_SALES.getValue()));
        //避免延迟消息操作中未知冲突执行导致的错误（不是同一次售后）
        if (!orderDetailDOS.isEmpty()) {
            Long afterSalesId = orderDetailDOS.get(0).getAfterSalesId();
            if (!afterSalesId.equals(salesId)) {
                throw exception(ORDER_STATUS_ERROR);
            }
        }
        orderDetailDOS.forEach(res -> {
            res.setAfterSalesId(null);
            res.setState(OrderDetailStateEnum.NORMAL.getValue());
        });
        orderDetailMapper.updateBatch(orderDetailDOS, orderDetailDOS.size());
    }

    /**
     * 售后处理
     *
     * @param salesId        售后id
     * @param orderCode      订单号
     * @param approvalStatus 审核状态1-同意 2-拒绝
     */
    private void salesCheck(Long salesId, String orderCode, Integer approvalStatus, String consignee, String phoneNumber, String address) throws Exception {
        StoreAfterSalesDO storeAfterSales = storeAfterSalesMapper.selectOne(Wrappers.<StoreAfterSalesDO>lambdaQuery()
                .eq(StoreAfterSalesDO::getOrderCode, orderCode).eq(StoreAfterSalesDO::getId, salesId));
        this.salesCheck(storeAfterSales, approvalStatus, consignee, phoneNumber, address);
    }

    /**
     * 添加订单操作记录
     */
    private void addOrderOptLog(Long uid, Long oid, AfterChangeTypeEnum afterChangeTypeEnum) {
        storeAfterSalesStatusService.create(uid, oid, afterChangeTypeEnum.getValue(), afterChangeTypeEnum.getDesc());
    }


    /**
     * 立即退款
     *
     * @param id 编号
     */
    @Override
    @Deprecated
    public void payStoreAfterSales(Long id) throws Exception {
        StoreAfterSalesDO storeAfterSales = storeAfterSalesMapper.selectOne(Wrappers.<StoreAfterSalesDO>lambdaQuery()
                .eq(StoreAfterSalesDO::getId, id));

        storeAfterSales.setState(AfterSalesStatusEnum.REFUND_SUCCESS.getValue());
        addOrderOptLog(storeAfterSales.getUserId(), storeAfterSales.getId(), AfterChangeTypeEnum.PAYMENT);
        // 退款参数
        AppOrderRefundParam param = new AppOrderRefundParam(id, storeAfterSales.getOrderCode(),
                storeAfterSales.getRefundAmount(), StockBackTypeEnum.DEFAULT.getValue(),
                storeAfterSales.getRefundIntegral(), BillDetailEnum.TYPE_13);
        appStoreOrderService.orderRefund(param);

    }


    private void validateStoreAfterSalesExists(Long id) {
        if (storeAfterSalesMapper.selectById(id) == null) {
            throw exception(STORE_AFTER_SALES_NOT_EXISTS);
        }
    }

    @Override
    public StoreAfterSalesDO getStoreAfterSales(Long id) {
        return storeAfterSalesMapper.selectById(id);
    }


    /**
     * 获得售后记录分页
     *
     * @param pageReqVO 分页查询
     * @return 售后记录分页
     */
    @Override
    public PageResult<StoreAfterSalesRespVO> getStoreAfterSalesPage(StoreAfterSalesPageReqVO pageReqVO) {
        PageResult<StoreAfterSalesDO> pageResult = storeAfterSalesMapper.selectPage(pageReqVO);
        PageResult<StoreAfterSalesRespVO> storeAfterSalesRespVOPageResult = StoreAfterSalesConvert.INSTANCE.convertPage(pageResult);
        for (StoreAfterSalesRespVO storeAfterSalesRespVO : storeAfterSalesRespVOPageResult.getList()) {
            LambdaQueryWrapper<StoreAfterSalesItemDO> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(StoreAfterSalesItemDO::getStoreAfterSalesId, storeAfterSalesRespVO.getId());
            List<StoreAfterSalesItemDO> storeAfterSalesItemDOS = storeAfterSalesItemMapper.selectList(wrapper);
            MemberUserDO memberUserDO = memberUserMapper.selectById(storeAfterSalesRespVO.getUserId());
            UserRespVO userRespVO = UserConvert.INSTANCE.convert4(memberUserDO);
            storeAfterSalesRespVO.setStoreOrderCartInfoDOList(storeAfterSalesItemDOS);
            storeAfterSalesRespVO.setUserRespVO(userRespVO);
        }
        return storeAfterSalesRespVOPageResult;
    }


}
